#pragma once
#include <unordered_map>
#include "net.hpp"

namespace myrpc{
    // 消息回调基类——抽象基类 主要是提供接口以及解决模板子类类型不一的问题
    class CallBack{
    public:
        using ptr=std::shared_ptr<CallBack>;
        virtual void onMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &msg) = 0;
    };
    // 由基类派生出的模板特定消息回调子类
    template<typename MType>
    class CallBackT : public CallBack {
    public:
        using ptr = std::shared_ptr<CallBackT<MType>>;
        using new_MessageCallBack = std::function<void(const BaseConnection::ptr &, std::shared_ptr<MType> &)>;

        CallBackT(const new_MessageCallBack &handler)
        :_handler(handler)
        {}
        void onMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &msg) override {
            // 将消息基类指针转换为特定的消息子类指针
            auto type_msg = std::dynamic_pointer_cast<MType>(msg);
            _handler(conn, type_msg);
        }
    
    private:
        new_MessageCallBack _handler;
    };

    class Dispatcher
    {
    public:
        using ptr = std::shared_ptr<Dispatcher>;

        template<typename MType>
        void registerHandler(MsgType mtype, const typename CallBackT<MType>::new_MessageCallBack &handler){
            std::unique_lock<std::mutex> lock(_mutex);
            // 创建特定消息回调的子类指针
            auto cb = std::make_shared<CallBackT<MType>>(handler);
            _handlers.insert(std::make_pair(mtype, cb));
        }

        void onMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &msg){
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _handlers.find(msg->getMsgType());
            if (it != _handlers.end()){
                return it->second->onMessage(conn, msg);
            }
            else{
                root_logger->ERROR("未找到此类型消息的回调处理程序! ID: %s", msg->getMsgId().c_str());
                conn->shutdown();
            }
        }

    private:
        std::mutex _mutex;
        //哈希表中不再直接存储特定消息的回调处理 而是封装后的消息回调的基类指针
        std::unordered_map<MsgType, CallBack::ptr> _handlers; 
    };
}